package org.game.manager;

import com.google.common.collect.Maps;
import com.google.protobuf.InvalidProtocolBufferException;
import com.sojoys.artifact.constant.ArtifactErrorCode;
import com.sojoys.artifact.constant.SessionStatusEnum;
import com.sojoys.artifact.factory.session.ISession;
import com.sojoys.artifact.manager.MessageManager;
import com.sojoys.artifact.manager.PropManager;
import com.sojoys.artifact.tools.ToolError;
import com.sojoys.artifact.tools.ToolMap;
import com.xiaoleilu.hutool.date.DateUnit;
import com.xiaoleilu.hutool.date.DateUtil;
import com.xiaoleilu.hutool.log.Log;
import com.xiaoleilu.hutool.log.LogFactory;
import com.xiaoleilu.hutool.util.MapUtil;
import io.netty.channel.ChannelFutureListener;
import org.base.BaseGoods;
import org.bean.AccountInfo;
import org.cache.GoodsCfgCache;
import org.cfg.AngelSkillTreeCfg;
import org.cfg.DiscreteDataCfg;
import org.cfg.LevelUpCfg;
import org.cfg.cache.AngelSkillTreeCfgCache;
import org.cfg.cache.DiscreteDataCfgCache;
import org.cfg.cache.LevelUpCfgCache;
import org.constant.*;
import org.error.GameErrorCode;
import org.error.LoginErrorCode;
import org.game.cache.OnlinePlayerCache;
import org.game.cache.ServerCache;
import org.game.constant.GameConstant;
import org.game.constant.QuartzCronExpressions;
import org.game.constant.SessionConstent;
import org.game.db.PlayerIdProvider;
import org.game.db.bean.*;
import org.game.db.cache.*;
import org.game.db.proxy.bean.PlayerDataProxy;
import org.game.db.proxy.bean.PlayerProxy;
import org.game.db.vo.*;
import org.game.db.vo.PlayerDataVO.DiscreteVO;
import org.game.log.LogPlayerAction;
import org.game.log.builder.LogDsp;
import org.game.log.dsp.GoodsDsp;
import org.game.log.dsp.PlayerActionDsp;
import org.game.module.core.Core;
import org.game.module.datingbo.trigger.CityDatingTriggerManager;
import org.game.module.datingbo.trigger.QuartzCityDatingTrigger;
import org.game.msgBuilder.HeroMsgBuilder;
import org.game.msgBuilder.ItemMsgBuilder;
import org.game.msgBuilder.PlayerMsgBuilder;
import org.game.plugin.event.GameEvent;
import org.game.plugin.event.GameEventPlugin;
import org.game.protobuf.s2c.S2CHeroMsg;
import org.game.protobuf.s2c.S2CItemMsg;
import org.game.protobuf.s2c.S2CItemMsg.ItemList;
import org.game.protobuf.s2c.S2CPlayerMsg.FormationInfoList;
import org.game.protobuf.s2c.S2CPlayerMsg.PlayerInfo;
import org.game.protobuf.s2c.S2CPlayerMsg.RespTargetPlayerInfo;
import org.game.protobuf.s2c.S2CShareMsg.ChangeType;
import org.game.util.ProtoUnit;
import org.game.util.QuartzUtils;
import org.script.ScriptArgs;
import org.script.ScriptManager;
import org.utils.RemoteUtil;

import java.util.*;
import java.util.Map.Entry;


/**
 * @author : DengYing
 * @CreateDate : 2017年7月11日 下午3:08:25
 * @Description ：玩家管理器
 */
public class PlayerManager {

	static Log log = LogFactory.get(PlayerManager.class);
	
	private PlayerManager() {
	}

	private static PlayerManager ME = new PlayerManager();

	public static PlayerManager me() {
		return ME;
	}
	
	private static ThreadLocal<Boolean> createPlayer = new ThreadLocal<Boolean>();

	public boolean isCreatePlayer() {
		return createPlayer.get() == null ? false : createPlayer.get();
	}

	/**
	 * 上线
	 * 
	 * @param player
	 */
	public void online(ISession session,Player player) {
		
		PlayerProxy playerExt = player.getPlayerProxy();
		
		// 玩家已在线
		ISession oldSession = playerExt.getSession();
		if (oldSession != null) {
			if(oldSession.getStatus() == SessionStatusEnum.RUNNING){
				if (player != null && player.getPlayerProxy().isOnline()) {
					PlayerManager.me().offline(player);
				}
				oldSession.setStatus(SessionStatusEnum.CLOSE);
			}
			io.netty.channel.Channel channel = oldSession.getChannel();
			channel.writeAndFlush(MessageManager.me().create(Core.logoutGame, LoginErrorCode.OFF_SITE_LANDING)).addListener(ChannelFutureListener.CLOSE);
		}
		
		
		// 重新初始化钥密
		session.setAttr(SessionConstent.ENCRYPTION_KEYS, new int[]{1,2,3,4,5,6,7,8});
		session.setAttr(SessionConstent.DECRYPTION_KEYS, new int[]{1,2,3,4,5,6,7,8});
		
		// 双向绑定
		session.setAttr(SessionConstent.PLAYER, player);
		
		// 设定Actor
		session.setAttr(SessionConstent.ACTOR, playerExt.getActorRef());
				
		playerExt.setSession(session);
		
		
		
		playerExt.setOnline(true);
		
		// 添加在线玩家缓存
		OnlinePlayerCache.addCache(player);
		
		// 装载玩家数据
		PlayerManager.me().loadPlayer(player);
		
		// 新的一天登陆
		int intervalDay = (int) DateUtil.betweenDay(player.getLastLoginTime(), new Date(), true);
		if (intervalDay > 0) {
			newDayLogin(player,intervalDay);
		}
		
		Date lastLoginDate = player.getLastLoginTime();
		Date nowDate = new Date();
		player.setLastLoginTime(nowDate);
		player.update();
		
		loginRefresh(player);
		
		// 线下奖励
		OfflineRewardManager.me().pullRewardInfo(player);
		
		// 修改PlayerInfo
		Map<Integer, Object> map = Maps.newHashMap();
		map.put(org.bean.PlayerInfo.ONLINE, true);
		map.put(org.bean.PlayerInfo.LAST_LOGIN_DATE, player.getLastLoginTime());
		ServerCache.getPlayerInfoByPid(player.getId()).upload(map);
		
		// 触发登陆事件
		Map<String, Object> in = Maps.newHashMap();
		in.put(EventConditionKey.LAST_LOGIN_DATE, lastLoginDate);
		in.put(EventConditionKey.NOW_LOGIN_DATE, nowDate);
		GameEvent event = new GameEvent(player, EventType.LOGIN, in);
		GameEventPlugin.syncSubmit(event);

		// 触发月卡事件
		in = Maps.newHashMap();
		in.put(EventConditionKey.CONDITION_TYPE, EventConditionType.GAIN_MONTH_CARD);
		event = new GameEvent(player, EventType.OTHER_EVENT, in);
		GameEventPlugin.syncSubmit(event);
		
		// 调用脚本(预留脚本，放在装载玩家数据后，方便以后修复线上bug)
        callLoginSuccessScript(player);
	}

	/**
	 * 登陆刷新(重置)
	 * @param player
	 */
	private void loginRefresh(Player player) {
		PlayerData playerData = player.getPlayerDatasFkPlayerId();
		PlayerDataProxy playerDataProxy = playerData.getPlayerDataProxy();
		// 重置玩家数据
		resetPlayerData(player);

		// 登陆成功刷新商店信息
		StoreManager.me().loginRefreshShop(player);

		// 登陆成功刷新副本次数
		DungeonManager.refreshDungeonCount(player);

		// 登陆成功检查任务
		TaskManager.me().checkTimeOutTasks(player);
		TaskManager.me().resetTasks(player);
		//删除临时约会（掉线后不能继续进行的约会）
		DatingManager.dealTempDating(player);
		//重置看板娘每日城市约会次数
		RoleManager.me().resetCityTriggerCountByLogin(player);
		//刷新城市约会
		CityDatingTriggerManager.refreshCityDating(player,new Date());
		// 登录成功刷新无尽回廊信息
		EndlessCloisterManager.me().loginRefresh(player);
		
	}

	/**
	 * 新的一天登陆
	 * @param player
	 * @param intervalDay 间隔天数
	 */
	private void newDayLogin(Player player,int intervalDay) {
		// 推送公告
		pushNotice(player);
	}

	/**
	 * 下线
	 * 
	 * @param player
	 */
	public void offline(Player player) {
		log.debug("offline player id:{} name:{}",player.getId(),player.getName());
		
		PlayerProxy playerExt = player.getPlayerProxy();
		String ip = playerExt.getSession().remoteAddress().toString();
		playerExt.setOnline(false);
		playerExt.setSession(null);
		OnlinePlayerCache.clearCache(player);
		player.update();
		
		// 上传玩家信息改变
		Map<Integer, Object> map = Maps.newHashMap();
		map.put(org.bean.PlayerInfo.ONLINE, false);
		map.put(org.bean.PlayerInfo.LAST_OFFLINE_DATE, new Date());
		ServerCache.getPlayerInfoByPid(player.getId()).upload(map);
		
		// 取得在线时间(秒)
		int onlineTime = (int) DateUtil.between(player.getLastLoginTime(), new Date(), DateUnit.SECOND);
		LogPlayerAction.me().log(player.getId(), onlineTime,ip, LogDsp.newBuilder(PlayerActionDsp.OFFLINE));
		RemoteUtil.loginSync().offline(player.getUid());
	}

	/**
	 * 创建player
	 * 后期优化可以做成对象池(提高玩家在推广期间爆发式增长体验)
	 * @param accountInfo
	 * @return
	 */
	public Player createPlayer(AccountInfo accountInfo,boolean pre) {
		// 取得一个Pid
//		int pid = RemoteUtil.socialSync().getNewPid();
		int pid = PlayerIdProvider.me().pollId();
		// 默认以玩家ID作为玩家名称
		String defaultPlayerName = String.valueOf(pid);
		
		ToolError.isAndTrue(ArtifactErrorCode.SERVER_BUSY,"服务器繁忙", pid < 10000000);
		
		
		DiscreteDataCfg cfg = DiscreteDataCfgCache.me().getById(DiscreteDataID.INIT_PLAYER);
		Map dataMap = cfg == null ? Maps.newHashMap() : cfg.getData();
		int initPlayerLevel = ToolMap.getInt("playerLevel", dataMap, 1);
		int initPlayerExp = ToolMap.getInt("playerExp", dataMap, 0);
		int initPlayerVipLevel = ToolMap.getInt("playerVipLevel", dataMap, 0);
		int initPlayerVipExp = ToolMap.getInt("playerVipExp", dataMap, 0);

		
		// 标明当前线程：执行过创建玩家操作
		createPlayer.set(true);

		// 初始化玩家
		Player player = new Player(pid, accountInfo.getUid(), accountInfo.getLanguage(), defaultPlayerName, new Date(),
				initPlayerLevel, initPlayerExp, initPlayerVipLevel, initPlayerVipExp,"",pre,new Date(),0);
		player.insert();
		
		
		// 创建离散数据
		PlayerData playerData = new PlayerData(0L, player.getId(), Maps.newHashMap());
		playerData.insert();
		
		// 初始化玩家阵型
		Formation formation = new Formation(0L, pid, FormationConstant.STATUS_USE, FormationConstant.TYPE_MAIN, new ArrayList<>(3));
		formation.insert();
		
		
		// 添加服务器玩家缓存
		ServerCache.putCache(player);
		player.getPlayerProxy().setAccountInfo(accountInfo);
		
		// 初始化玩家物品
		Map<Integer, Integer> goods = ToolMap.getMap("goods", dataMap,Maps.newHashMap());
		// 体力
//		LevelUpCfg levelUpCfg = LevelUpCfgCache.me().getById(player.getLevel());
//		int energy = levelUpCfg.getMaxEnergy();
//		goods.put(ItemConstantId.ENERGY, energy);
		LogDsp log = LogDsp.newBuilder(GoodsDsp.CREATE_PLAYER);
		ItemManager.addGoods(player, null, null,ItemList.newBuilder(),log, goods);
		
		// * 并非与上面重复代码。不可删除
		ServerCache.putCache(player);

		// 远程创建新的玩家信息
		org.bean.PlayerInfo uploadPlayerInfo = ServerCache.getPlayerInfoByPid(player.getId());
		RemoteUtil.socialAsyn().createPlayerMap(accountInfo,uploadPlayerInfo);
		
		return player;
	}

	/**
	 * 增加玩家经验
	 * @param player
	 * @param addExp
	 */
	public int addExp(Player player, long addExp) {
		int nowLv = player.getLevel();
		int oldLv = player.getLevel();
		DiscreteDataCfg discreteData = DiscreteDataCfgCache.me().getById(DiscreteDataID.MAX_LVL_CONFIG);
		int maxLvl = ToolMap.getInt("pmaxlvl", discreteData.getData(),0);
		LevelUpCfg nextLvl = LevelUpCfgCache.me().getById(nowLv + 1);
		if (nextLvl==null || nowLv > maxLvl) {
			return 0;
		}

		int actualAddExp = 0;

		int addAP = 0;
		
		LevelUpCfg nowLvl = null;
		while (addExp > 0) {
			long total = player.getExp() + addExp;
			nowLvl = LevelUpCfgCache.me().getById(nowLv);
			if (nowLvl==null) {
				break;
			}
			long maxExp = nowLvl.getPlayerExp();
			
			nextLvl = LevelUpCfgCache.me().getById(nowLv + 1);
			addExp = total - maxExp;
			if (addExp >= 0 && nextLvl != null && nextLvl.getId() <= maxLvl) {
				nowLv+=1;
				player.setExp(0);
				addAP+=nowLvl.getRecovery();
				actualAddExp += maxExp;
			}else {
				actualAddExp += total - player.getExp();
				player.setExp(Math.min(total, maxExp));
				break;
			}
		}

		if (nowLv!=oldLv) {
			
			
			
			player.setLevel(nowLv);
			Map<Integer, Integer> goods = MapUtil.of(ItemConstantId.AP, addAP);
			LogDsp log = LogDsp.newBuilder(GoodsDsp.PLAYER_LVL_UP).targetTag(nowLv);
			ItemManager.addGoodsAndPush(player, null, null, goods, log);
			
			// 体力上限改变
//			BaseGoods baseGoods = GoodsCfgCache.me().get(ItemConstantId.AP);
//			BackpackVO backpackVO = player.getBackpackByType(baseGoods.getBagType());
//			ItemManager.checkAutoRecover(player, baseGoods, backpackVO);
			
			
			Map<Integer, Object> map = Maps.newHashMap();
			map.put(org.bean.PlayerInfo.LVL, player.getLevel());
			ServerCache.getPlayerInfoByPid(player.getId()).upload(map);
			
			
			// 触发任务激活事件
			Map<String, Object> in = Maps.newHashMap();
			GameEvent event = new GameEvent(player, EventType.TASK_ACCEPT, in);
			GameEventPlugin.syncSubmit(event);
			
			// 触发玩家等级事件
			in = Maps.newHashMap();
			in.put(EventConditionKey.CONDITION_TYPE, EventConditionType.PLAYER_LVL);
			in.put(EventConditionKey.OLD_LEVEL, oldLv);
			in.put(EventConditionKey.NOW_LEVEL, nowLv);
			event = new GameEvent(player, EventType.PLAYER_CHANGE, in);
			GameEventPlugin.syncSubmit(event);
			String ip = player.getPlayerProxy().getSession().remoteAddress().toString();
			LogPlayerAction.me().log(player.getId(), 0,ip,LogDsp.newBuilder(PlayerActionDsp.UP_LVL));
		}
		player.update();


		PlayerInfo.Builder playerBuilder = PlayerInfo.newBuilder();
		playerBuilder.setLvl(player.getLevel());
		playerBuilder.setExp(player.getExp());
		player.getPlayerProxy().sendMsg(MessageManager.me().create(Core.getPlayerInfo,ProtoUnit.toByte(playerBuilder.build())));
		return actualAddExp;
	}
	
	/**
	 * 推送公告消息
	 * @param player
	 */
	public void pushNotice(Player player){
//		NoticeList.Builder builder = NoticeList.newBuilder();
//		Map<Integer, Notice> notices = NoticeCache.getAllNotice();
//		for (Entry<Integer, Notice> e : notices.entrySet()) {
//			Notice notice = e.getValue();
//			NoticeInfo.Builder info = NoticeInfo.newBuilder();
//			info.setContext(notice.getContext());
//			info.setContextImg(notice.getContextImg());
//			info.setId(notice.getId());
//			info.setInx(notice.getInx());
//			info.setTag(notice.getTag());
//			info.setTitle(notice.getTitle());
//			info.setType(notice.getType());
//			builder.addInfo(info.build());
//		}
//		player.getPlayerProxy().sendMsg(MessageManager.me().create(Core.pushNotice, ProtoUnit.toByte(builder.build())));
	}
	
	// 改变精灵心情(文档改变)
//	public void changeRoleMood(Player player,int intervalDay){
//		DiscreteDataCfg cfg = DiscreteDataCfgCache.me().getById(DiscreteDataID.ROLE_MOOD);
//		List<Map<String, Integer>> configs = ToolMap.getList(DiscreteDataKey.LIST, cfg.getData()); 
//		List<Role> roles = player.getRolesFkPlayerId();
//		for (int i = 0; i < intervalDay; i++) {
//			for (Role role : roles) {
//				// 取得心情值
//				int oldMood = role.getMood();
//				int addMood = 0;
//				for (Map<String, Integer> config : configs) {
//					int ceiling = ToolMap.getInt(DiscreteDataKey.CEILING, config);
//					int floor = ToolMap.getInt(DiscreteDataKey.FLOOR, config);
//					// 小于天花板 & 大于等于地板
//					if (oldMood < ceiling && oldMood >= floor) {
//						int min = ToolMap.getInt(DiscreteDataKey.MIN, config);
//						int max = ToolMap.getInt(DiscreteDataKey.MAX, config);
//						int num = ToolRandom.randInt(min, max);
//						addMood=num;
//						break;
//					}
//				}
//				
//				if (addMood!=0) {
//					role.setMood(oldMood + addMood);
//					role.update();					
//				}
//			}
//		}
//	}

	public void loadPlayer(Player player) {
	    callPreLoadPlayerScript(player);
		PlayerProxy playerExt = player.getPlayerProxy();
		// 初始玩家背包
		List<Item> items = player.getItemsFkPlayerId();
		Collection<BackpackVO> backpacks = playerExt.getBackpacks();
		for (BackpackVO backpackVO : backpacks) {
			backpackVO.clear();
		}
		for (Item item : items) {
			BaseGoods baseGoods = GoodsCfgCache.me().get(item.getCid());
			BackpackVO backpackVO = playerExt.getBackpackByType(baseGoods.getBagType());
			backpackVO.addItem(item);
			
			if (baseGoods.getSuperType() == ItemType.DRESS) {
				DressVO vo = (DressVO) item;
				long roleId = vo.getRoleId();
				if (roleId != 0) {
					Role role = RoleCache.me().getById(roleId);
					role.getRoleProxy().setDressVO(vo);
				}
			}else if (baseGoods.getSuperType() == ItemType.EQUIP){
				EquipmentVO equipmentVO = (EquipmentVO) item;
				long heroId = equipmentVO.getHeroId();
				if (heroId != 0) {
					Hero hero = HeroCache.me().getById(heroId);
					hero.getHeroProxy().getEquipment().put(equipmentVO.getPosition(), equipmentVO);
				}
			}else if (baseGoods.getSuperType() == ItemType.SKIN){
				SkinVO skinVO = (SkinVO) item;
				long heroId = skinVO.getHeroId();
				if (heroId != 0){
					Hero hero = HeroCache.me().getById(heroId);
					hero.getHeroProxy().setSkinVo(skinVO);
				}
			}else if (baseGoods.getSuperType() == ItemType.ROOM){
				RoomVO roomVO = (RoomVO) item;
				long roleId = roomVO.getRoleId();
				if (roleId != 0){
					Role role = RoleCache.me().getById(roleId);
					RoleManager.changeRoom(role,roomVO);
				}
			}

		}
//		player.setBag(bag);
		
		PlayerData playerData = player.getPlayerDatasFkPlayerId();
		int helpFightHeroCid = playerData.getPlayerDataProxy().getDiscreteVO().getHelpFigntHeroCid();
		
		// 初始化玩家英雄
		List<Hero> heros = player.getHerosFkPlayerId();
		AngelSkillTreeCfg cfg = null;
		for (Hero hero : heros) {
			Map<String, Integer> angel = hero.getAngel();
			int alreadyUseSkillPiont = 0;
			for (Entry<String, Integer> e : angel.entrySet()) {
				String[] key = e.getKey().split("_");
				int type = Integer.valueOf(key[0]);
				int pos = Integer.valueOf(key[1]);
				int val = e.getValue();
				cfg = AngelSkillTreeCfgCache.me().getByHeroIdSkillTypePosLvl(hero.getCid(), type, pos, val);
				alreadyUseSkillPiont += cfg.getSumOccupiedSkillPiont();
			}
			hero.getHeroProxy().setAlreadyUseSkillPiont(alreadyUseSkillPiont);
			// 计算英雄属性
			HeroManager.me().calAttr(hero);
			
			playerExt.getHerosByDbId().put(hero.getId(), hero);

			playerExt.getHerosByCid().put(hero.getCid(), hero);

			// 设置助战英雄
			if (hero.getCid() == helpFightHeroCid) {
				playerExt.setHelpHero(hero);				
			}
		}
		
		
		// 初始化玩家精灵
		List<Role> roles = player.getRolesFkPlayerId();
		for (Role role : roles) {
			playerExt.getRoles().put(role.getId(), role);
			if(role.getStatus() == RoleConstant.STATUS_USE){
				playerExt.setCurrentRole(role);
			}
			// 修正：没有时装
			if (role.getRoleProxy().getDressVO() == null) {
				BackpackVO backPackVO = player.getPlayerProxy().getBackpackByType(BagType.Dress);
				int[] dress = role.getRoleProxy().getConfig().getDress();
				for (int cid : dress) {
					List<Item> list = backPackVO.getItemList(cid);
					if (list == null || list.isEmpty()) {
						continue;
					}
					Item dres = list.get(0);
					if (dres instanceof DressVO) {
						DressVO dressVO = (DressVO) dres;
						long oldRoleId = dressVO.getRoleId();
						if (oldRoleId == 0) {
							role.getRoleProxy().setDressVO(dressVO);
							dressVO.setRoleId(role.getId());
							dressVO.update();
						}
					}
				}
				
				ToolError.isAndTrue(GameErrorCode.PLAYER_DATA_ERROR, role.getRoleProxy().getDressVO() == null);
			}
			
			
			QuartzUtils.outQuartzUpdate(QuartzCronExpressions.ROLE_MOOD_UPDATE_TIME,role.getRoleProxy().new MoodUpdater());
		}
		QuartzUtils.outQuartzRefresh(QuartzCronExpressions.INVITE_DATING_TIME,new QuartzCityDatingTrigger(player));
		
		// 玩家阵型
		List<Formation> formations = player.getFormationsFkPlayerId();
		for (Formation formation : formations) {
			if (formation.getStatus() == FormationConstant.STATUS_USE) {
				playerExt.setCurrentFormation(formation);
				break;
			}
		}
		
		// 检查活动
		ActivityManager.me().checkActivityChange(player);
		
		// 触发任务激活事件，如果策划新加了任务，进入游戏就会去接该任务
		Map<String, Object> in = Maps.newHashMap();
		in.put(EventConditionKey.LOAD_PLAYER, true);
		GameEvent event = new GameEvent(player, EventType.TASK_ACCEPT, in);
		GameEventPlugin.syncSubmit(event);
	}
	
	
	public byte[] getLocalTargetPlayerInfo(int targetPid) {
		Player targetPlayer = PlayerCache.me().getById(targetPid);
		
		if (!targetPlayer.getPlayerProxy().isOnline()) {
			PlayerManager.me().loadPlayer(targetPlayer);	
		}
		
		
		ToolError.isAndTrue(GameErrorCode.CLIENT_PARAM_IS_ERR, targetPlayer == null);
		// 取得玩家信息
		RespTargetPlayerInfo.Builder builder = RespTargetPlayerInfo.newBuilder();
		builder.setPlayerInfo(PlayerMsgBuilder.createPlayerInfo(targetPlayer));
		
		// 取得主阵
//		Formation formation = FormationCache.me().getByPlayerIdType(targetPlayer.getId(), FormationConstant.TYPE_MAIN);
		List<Formation> formations = FormationCache.me().getByPlayerId(targetPlayer.getId());
		FormationInfoList formationInfoList = PlayerMsgBuilder.createFormationInfoList(ChangeType.DEFAULT, formations);
		builder.setFormationInfo(formationInfoList);
		
		// 取得英雄
		List<Hero> heros = targetPlayer.getHerosFkPlayerId();
		for (Hero hero : heros) {
			builder.addHeros(HeroMsgBuilder.createHeroInfo(ChangeType.DEFAULT, hero));
		}
		
		// 取得装备
		List<Item> items = ItemCache.me().getByPlayerId(targetPlayer.getId());
		for (Item item : items) {
			BaseGoods goods = GoodsCfgCache.me().get(item.getCid());
	        if (goods.getSuperType() == ItemType.EQUIP) {
	            builder.addEquipments(ItemMsgBuilder.createEquipmentInfo(ChangeType.DEFAULT, (EquipmentVO) item));
	        }
		}
		
		return ProtoUnit.toByte(builder.build());
	}
	
	

	public RespTargetPlayerInfo getRemoteTargetPlayerInfoByPid(int targetPid)  {
		org.bean.PlayerInfo playerInfo = RemoteUtil.socialSync().getPlayerInfo(targetPid);
		String serverId = playerInfo.getServerId();
		byte[] bytes = null;
		// 如果是本服直接提取
		if (PropManager.get(GameConstant.GAME_SERVER_ID).equals(serverId)) {
			bytes = getLocalTargetPlayerInfo(targetPid);
		} else {
			bytes = RemoteUtil.gameSync(serverId).getTargetPlayerInfo(targetPid);
		}
		try {
			return RespTargetPlayerInfo.parseFrom(bytes);
		} catch (InvalidProtocolBufferException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 获取助战英雄信息
	 */
	public S2CHeroMsg.HeroInfo getRemoteHeroInfo(int targetPid, int heroCid){
		org.bean.PlayerInfo playerInfo = RemoteUtil.socialSync().getPlayerInfo(targetPid);
		String serverId = playerInfo.getServerId();
		byte[] bytes = null;
		// 如果是本服直接提取
		if (PropManager.get(GameConstant.GAME_SERVER_ID).equals(serverId)) {
			bytes = getLocalHeroInfo(targetPid,heroCid);
		} else {
			bytes = RemoteUtil.gameSync(serverId).getHelpHeroInfo(targetPid,heroCid);
		}
		try {
			return S2CHeroMsg.HeroInfo.parseFrom(bytes);
		} catch (InvalidProtocolBufferException e) {
			e.printStackTrace();
		}
		return null;

	}

	/**
	 * 获取助战英雄信息
	 */
	public byte[] getLocalHeroInfo(int playerId,int heroCid){
		Player targetPlayer = PlayerCache.me().getById(playerId);

		if (!targetPlayer.getPlayerProxy().isOnline()) {
			PlayerManager.me().loadPlayer(targetPlayer);
		}

		Hero hero  = targetPlayer.getPlayerProxy().getHelpHero();
		if (hero.getCid() != heroCid){
			List<Hero> heroList = HeroCache.me().getByPlayerId(playerId);
			hero = heroList.stream()
					.filter(h->h.getCid() == heroCid)
					.findFirst().orElse(null);
		}
		ToolError.isAndTrue(GameErrorCode.NOT_FOND_HERO,"",hero == null);
		return HeroMsgBuilder.createHeroInfo(ChangeType.DEFAULT,hero).toByteArray();
	}

	/**
	 * 取得玩家数据代理
	 * @param player
	 * @return
	 */
	public PlayerDataProxy getDataProxy(Player player){
		PlayerData playerData = player.getPlayerDatasFkPlayerId();
		return playerData.getPlayerDataProxy();
	}
	
	/**
	 * 重置玩家数据
	 */
	public void resetPlayerData(Player player){
		PlayerDataProxy proxy = getDataProxy(player);
		DiscreteVO discreteVO = proxy.getDiscreteVO();
		Date nowDate = new Date();
		
		// 检查 & 重置 活跃
		Date lasetResetActiveDate = discreteVO.getLastResetActiveDate();
		if(DateUtil.betweenDay(lasetResetActiveDate, nowDate, true) > 0){
			BackpackVO backVO = player.getPlayerProxy().getBackpackByGoodsCid(ItemConstantId.PLAYER_ACTIVE);
			if (backVO!=null) {
				int count = backVO.countByCfg(ItemConstantId.PLAYER_ACTIVE);
				if (count > 0) {
					LogDsp log = LogDsp.newBuilder(GoodsDsp.RESET);
					ItemManager.me().costGoodsByCid(player, MapUtil.of(ItemConstantId.PLAYER_ACTIVE, count), log, S2CItemMsg.ItemList.newBuilder());
				}
				discreteVO.setLastResetActiveDate(nowDate);
				proxy.save();
			}
		}
		
		// 清空天使每天免费重置次数
		Date lastClearResetAngelDate = discreteVO.getLastClearResetAngelDate();
		if(DateUtil.betweenDay(lastClearResetAngelDate, nowDate, true) > 0){
			discreteVO.setResetAngelCount(0);
			discreteVO.setLastClearResetAngelDate(nowDate);
			proxy.save();
		}
	}
	
	/** 调用player加载数据预处理脚本 */
    private void callPreLoadPlayerScript(Player player) {
        ScriptArgs args = new ScriptArgs();
        args.put(ScriptArgs.Key.PLAYER, player);
        ScriptManager.getInstance().call("logic.login.PreLoadPlayerScript", args);
    }
	
	/** 调用登录成功脚本 */
    private void callLoginSuccessScript(Player player) {
        ScriptArgs args = new ScriptArgs();
        args.put(ScriptArgs.Key.PLAYER, player);
        ScriptManager.getInstance().call("logic.login.LoginSuccessScript", args);
    }
}
